#include <gtest/gtest.h>
#include <gmock/gmock.h>
#include <thread>
#include <unistd.h>
#include "rtdev/jk_bp/bp_intf.h"
#include "rtbus/rtbus.h"
#include <cstring>

using ::testing::_;
using ::testing::DoAll;
using ::testing::Invoke;
using ::testing::Return;
using ::testing::SetArgPointee;
using ::testing::SetArrayArgument;

template <typename T> void adapt_void_ptr(void* ptr, T value)
{
    printf("\n[adapt_void_ptr] exec!\n");
    printf("[adapt_void_ptr] size:%ld \n", sizeof(T));
    // 打印 value 的值
    if constexpr (std::is_floating_point<T>::value)
    {
        printf("[adapt_void_ptr] value: %f\n", value);  // 对于浮点类型
    }
    else if constexpr (std::is_same<T, std::string>::value)
    {
        printf("[adapt_void_ptr] value: %s\n", value.c_str());  // 对于 std::string 类型
    }
    else if constexpr (std::is_same<T, uint32_t>::value)
    {
        printf("[adapt_void_ptr] uint32_t value: %u\n", value);  // 对于 uint_8 类型
    }
    else if constexpr (std::is_same<T, uint64_t>::value)
    {
        printf("[adapt_void_ptr] uint64_t value: %lu\n", value);  // 对于 uint_8 类型
    }
    else if constexpr (std::is_integral<T>::value)
    {
        printf("[adapt_void_ptr] value: %d\n", value);  // 对于整数类型
    }
    else
    {
        printf("[adapt_void_ptr] value: (unsupported type)\n");  // 不支持的类型
    }
    if (ptr)
    {
        memcpy(ptr, &value, sizeof(T));
    }
}

class MockRtCommuItf : public rtbus::RtCommuItf
{
public:
    // MOCK_METHOD 用于模拟纯虚函数
    MOCK_METHOD(int, open, (rtbus::RtCommuItf::BusCfg cfg), (override));
    MOCK_METHOD(void, close, (), (override));
    MOCK_METHOD(int, active, (), (override));
    MOCK_METHOD(int, deactive, (), (override));
    MOCK_METHOD(int,
                register_sdo_handle,
                (uint8_t slave_id, uint32_t write_req_frame_id, uint32_t read_req_frame_id, uint32_t resp_frame_id, size_t obj_id_size),
                (override));
    MOCK_METHOD(void, send, (), (override));
    MOCK_METHOD(void, recv, (int64_t*), (override));
    MOCK_METHOD(void, reset, (), (override));
    MOCK_METHOD(bool, is_actived, (), (override));
    MOCK_METHOD(int, get_sdo, (uint8_t slave_id, uint32_t obj_id, std::function<int(uint8_t*, int)> cb, int timeout, int retry), (override));
    MOCK_METHOD(int,
                set_sdo,
                (uint8_t slave_id, uint32_t obj_id, uint8_t val[4], size_t size, std::function<int(uint8_t*, int)> cb, int timeout, int retry),
                (override));
    MOCK_METHOD(int, config_txpdo, (uint32_t obj, size_t size), (override));
    MOCK_METHOD(int, config_rxpdo, (uint32_t obj, size_t size), (override));
    MOCK_METHOD(int, set_txpdo_data, (uint32_t obj, uint8_t* data), (override));
    MOCK_METHOD(int, get_rxpdo_data, (uint32_t obj, uint8_t* data), (override));
    MOCK_METHOD(int, get_sdo_blocking, (uint8_t slave_id, uint32_t objid, void* data, int data_len, int retry), (override));
};

// 测试类初始化
class JkBpTest : public ::testing::Test
{
protected:
    std::shared_ptr<rtdev::ButtonPanelItf> board;
    std::shared_ptr<MockRtCommuItf> mockBus;
    void SetUp() override
    {
        printf("\n[JkBpTest] SetUp\n");
        board = std::make_shared<rtdev::ButtonPanelItf>();
        mockBus = std::make_shared<MockRtCommuItf>();
        board->bus_ = mockBus;
    }
    void TearDown() override
    {
        printf("\n[JkBpTest] TearDown\n");
        mockBus.reset();
        board.reset();
    }
};

// 测试接收pdo 0x191
TEST_F(JkBpTest, TioGetPdo)
{
    int alive_rt = 0;
    EXPECT_CALL(*mockBus, get_rxpdo_data(_, _)).WillRepeatedly(Return(0));
    EXPECT_CALL(*mockBus, get_rxpdo_data(rtdev::BP_STATUS_R, _))
        .Times(1)
        .WillOnce(DoAll(
            [](uint32_t objid, uint8_t* data) {
                uint8_t cmd_data[8] = {0b1,
                                       0b11,
                                       static_cast<uint8_t>(rtdev::BpColor::BP_RGB_RED),
                                       90,
                                       static_cast<uint8_t>(rtdev::BpColor::BP_RGB_YELLOW),
                                       80,
                                       0,
                                       0};  //构造0x191报文 蜂鸣器响，使能和电源按键被按下，
                adapt_void_ptr(data, *(uint64_t*)cmd_data);
                return 0;
            },
            Return(alive_rt++)));  //模拟自增量

    board->get_recv_data(1);  //mock模拟返回固定值，所以不需要set
    EXPECT_EQ(board->bp()->bp_status_.bp_beep, 1);
    EXPECT_EQ(board->bp()->bp_status_.key_buffer, 0b11);
    EXPECT_EQ(board->bp()->bp_status_.bp_rgb_lock_color, rtdev::BpColor::BP_RGB_RED);
    EXPECT_EQ(board->bp()->bp_status_.bp_rgb_lock_brightness, 90);
    EXPECT_EQ(board->bp()->bp_status_.bp_rgb_logol_color, rtdev::BpColor::BP_RGB_YELLOW);
    EXPECT_EQ(board->bp()->bp_status_.bp_rgb_logol_brightness, 80);
    EXPECT_EQ(board->bp()->bp_status_.heartbeat, 0);
}

// 测试接收pdo 0x211
TEST_F(JkBpTest, TioSetPdo)
{
    int alive_rt = 0;
    uint8_t cmd_data[8] = {0};
    EXPECT_CALL(*mockBus, set_txpdo_data(_, _)).WillRepeatedly(Return(alive_rt++));
    EXPECT_CALL(*mockBus, set_txpdo_data(rtdev::BP_STATUS_W, _)).Times(1).WillOnce(Return(alive_rt++));
    EXPECT_EQ(board->bp()->set_bp_beep(1), 0);
    EXPECT_EQ(board->bp()->bp_cmd_.bp_beep, 0b1);
    EXPECT_EQ(board->bp()->set_bp_logo_color(rtdev::BpColor::BP_RGB_RED), 0);
    EXPECT_EQ(board->bp()->bp_cmd_.bp_rgb_logol_color, rtdev::BpColor::BP_RGB_RED);
    EXPECT_EQ(board->bp()->set_bp_lock_color(rtdev::BpColor::BP_RGB_YELLOW), 0);
    EXPECT_EQ(board->bp()->bp_cmd_.bp_rgb_lock_color, rtdev::BpColor::BP_RGB_YELLOW);
    EXPECT_EQ(board->bp()->set_bp_logo_brightness(55), 0);
    EXPECT_EQ(board->bp()->bp_cmd_.bp_rgb_logol_brightness, 55);
    EXPECT_EQ(board->bp()->set_bp_lock_brightness(88), 0);
    EXPECT_EQ(board->bp()->bp_cmd_.bp_rgb_lock_brightness, 88);
    board->set_send_data(1);  //mock模拟返回固定值，所以不需要set
}